import fs from 'fs'
import path from 'path'

import koa from 'koa'
import parser from 'koa-bodyparser'
import { Sequelize } from 'sequelize-typescript'

import { catchError } from '@core/middleware/exception'
import config from '@config/index'
import UserModel from '@app/model/user'
import BillModel from '@app/model/bill'
import RecordModel from '@app/model/record'
import InterestLogModel from '@app/model/interest-log'

class InitManager {
  public static app: koa

  /**
   * 入口方法
   *    第1步，添加「body(上下文请求体)解析」功能
   *    第2步，载入config配置项
   *    第3步，连接数据库
   *    第4步，全局载入异常，可以用global.errs
   *    第5步，Koa实例添加路由
   *
   * @param app {koa} Koa实例
   * */
  static async initCore(app: koa) {
    // 静态方法中，this 是 InitManager; app 是Koa实例, 成为类属性
    this.app = app
    this.app.use(parser())
    this.loadConfig()
    if (global.config.connectDB) await this.connectDB()
    this.handleError()
    this.initLoadRouters('/app/api/v1', '/app/api/system')
  }

  static loadConfig() {
    global.config = config
  }

  /**
   * 批量载入路由
   *
   * @param routerPathList 路由所在目录列表 system、v1、v2
   */
  static initLoadRouters(...routerPathList: string[]) {
    // 载入
    routerPathList.forEach((routerPath) => {
      const basePath = process.env.NODE_ENV === 'production' ? 'dist' : 'src'
      const fullPath = path.join(process.cwd(), basePath, routerPath)
      if (fs.existsSync(fullPath)) {
        fs.readdirSync(fullPath).forEach(
          (file: string) => {
            if (file.indexOf('.') !== 0 && (file.slice(-3) === '.js' || file.slice(-3) === '.ts')) {
              const filePath = path.join(fullPath, file)
              require(filePath)
            }
          },
        )
      } else {
        console.warn(`Warning: Directory ${fullPath} does not exist`)
      }
    })

    const { routerList } = require('./decorator')
    // @ts-ignore
    routerList.forEach((router) => this.app.use(router.routes()))
  }

  /**
   *  载入所有自定义异常
   */
  static handleError() {
    global.errs = require('./exception')
    this.app.use(catchError)
  }

  /**
   * 连接数据库
   */
  static async connectDB() {
    try {
      const { dbName, host, port, username, password, force, logging } = global.config.database
      console.log('Connecting to database:', { host, port, dbName, username })

      const sequelize = new Sequelize(dbName, username, password, {
        dialect: 'mysql',
        host,
        port,
        logging,
        timezone: '+08:00', // 设置时区
        define: {
          timestamps: true,
          paranoid: true, // 增加 deletedAt
          createdAt: 'created_at',
          updatedAt: 'updated_at',
          deletedAt: 'deleted_at',
          underscored: true, // snake
        },
        models: [
          UserModel,
          BillModel,
          RecordModel,
          InterestLogModel,
        ],
      })

      // 测试连接
      await sequelize.authenticate()
      console.log('Database connection has been established successfully.')

      // 同步模型
      await sequelize.sync({ force })
      console.log('Database models have been synchronized.')
    } catch (error) {
      console.error('Unable to connect to the database:', error)
      throw error
    }
  }
}

export default InitManager
